namespace KinonekoSoftware.CodariaDB.Documents.Timelines
{
    partial class TimelineSystem
    {
        //-------------------------------------------------------------
        //
        //         Readonly  Fields
        //
        //-------------------------------------------------------------
        private readonly Dictionary<string, EpochNode> _mapOfEpoch;

        //-------------------------------------------------------------
        //
        //          Fields
        //
        //-------------------------------------------------------------
        private int       _CountOfEpoch;
        private int       _VersionOfEpoch;
        private EpochNode _RootNodeOfEpoch;

        //-------------------------------------------------------------
        //
        //          Private Methods
        //
        //-------------------------------------------------------------

        private void PerformEpochCollection(IEnumerable<EpochNode> collection)
        {
            //
            //
            Epoch = null;

            //
            //
            EpochCollection.AddMany(collection.Select(x => x.Value), true);
            EpochCollection.Sort();

        }

        private void PerformEpochLayer()
        {
            //
            //
            var parent = EpochLayer is null ? _RootNodeOfEpoch : _mapOfEpoch[EpochLayer.Id];

            //
            //
            PerformEpochCollection(parent.Children);
        }

        //-------------------------------------------------------------
        //
        //          Rebuild
        //
        //-------------------------------------------------------------
        public void RebuildEpoches()
        {
            //
            // 清空状态
            ClearEpochStates();

            //
            //
            var epoches = _system.GetEpochs();
            var root    = new List<EpochNode>(8);

            //
            // 第一遍遍历，旨在将所有节点都添加到字典当中。
            foreach (var epoch in epoches)
            {
                //
                //
                var node = new EpochNode(epoch);
                //
                //
                _mapOfEpoch.TryAdd(epoch.Id, node);

                if (string.IsNullOrEmpty(epoch.ParentID))
                {
                    root.Add(node);
                    _RootNodeOfEpoch.AddChildAndSetParent(node);
                    _VersionOfEpoch++;
                }

                _CountOfEpoch++;
            }

            //
            // 第二遍遍历，恢复树形结构
            foreach (var epoch in _mapOfEpoch.Values.Where(x => !string.IsNullOrEmpty(x.ParentID)))
            {
                if (_mapOfEpoch.TryGetValue(epoch.ParentID, out var parent))
                {
                    parent.AddChildAndSetParent(parent);
                }
                else
                {
                    epoch.ParentID = null;
                    _RootNodeOfEpoch.AddChildAndSetParent(epoch);

                    _system.Update(epoch.Value);
                }

                _VersionOfEpoch++;
            }

            //
            // 第三步，呈现UI
            PerformEpochCollection(root);
        }

        private void ClearEpochStates()
        {
            _RootNodeOfEpoch?.Children.Clear();
            _RootNodeOfEpoch = null;
            _RootNodeOfEpoch = new EpochNode();
            
            //
            //
            _mapOfEpoch.Clear();

            Epoch      = null;
            EpochLayer = null;
            EpochCollection.Clear();
            EpochLayerList.Clear();

            _VersionOfEpoch++;
            _CountOfEpoch = 0;
        }

        //-------------------------------------------------------------
        //
        //          Layer Methods
        //
        //-------------------------------------------------------------
        public Epoch PopEpochLayer()
        {
            if (EpochLayerList.Count < 1)
            {
                ResetEpochLayer();
                return null;
            }

            EpochLayerList.RemoveAt(EpochLayerList.Count - 1);

            if (EpochLayerList.Count == 0)
            {
                PushEpochLayer(null);
                return null;
            }

            EpochLayer = EpochLayerList[^1];

            PerformEpochLayer();
            return EpochLayer;
        }

        public void PushEpochLayer(Epoch epoch)
        {
            if (epoch is null)
            {
                EpochLayer = null;
                EpochLayerList.Clear();
            }
            else
            {
                EpochLayer = epoch;
                EpochLayerList.Add(epoch);
            }
            
            PerformEpochLayer();
        }

        public void ResetEpochLayer()
        {
            EpochLayer = null;
            EpochLayerList.Clear();
            PerformEpochLayer();
        }


        //-------------------------------------------------------------
        //
        //          Private Methods
        //
        //-------------------------------------------------------------

        //-------------------------------------------------------------
        //
        //          SubTree Methods
        //
        //-------------------------------------------------------------

        protected internal void UpdateSubtree(EpochNode parent)
        {
            if (parent.Children.Count == 0)
            {
                return;
            }

            for (var i = 0; i < parent.Children.Count; i++)
            {
                //
                //
                var child = parent.Children[i];
                var value = Epoch.Inherit(parent.Value, (byte)(i + 1));

                //
                //
                child.EpochValue = value;

                //
                // Update
                _system.Update(child.Value);

                //
                // recursive update
                UpdateSubtree(child);
            }
        }

        public IEnumerable<EpochNode> GetSubTree(Epoch value)
        {
            if (value is null)
            {
                return Array.Empty<EpochNode>();
            }

            var node = _mapOfEpoch.GetValueOrDefault(value.Id, null);

            if (node is null)
            {
                return Array.Empty<EpochNode>();
            }

            return GetSubTree(node);
        }

        protected internal static IEnumerable<EpochNode> GetSubTree(EpochNode node)
        {
            if (node is null)
            {
                return Array.Empty<EpochNode>();
            }

            var queue = new Queue<EpochNode>();
            var array = new List<EpochNode>(32);

            if (node is null)
            {
                return Array.Empty<EpochNode>();
            }

            queue.Enqueue(node);

            while (queue.Count > 0)
            {
                var item = queue.Dequeue();

                if (item.Children.Count > 0)
                {
                    foreach (var child in item.Children)
                    {
                        queue.Enqueue(child);
                        array.Add(child);
                    }
                }
            }

            return array.Count > 0 ? array : Array.Empty<EpochNode>();
        }

        protected internal void ChangeParent(EpochNode parent, int index, List<EpochNode> children)
        {
            if (children.Count == 0)
            {
                return;
            }

            if (parent.Children.Count + children.Count > 254)
            {
                throw new InvalidOperationException("要删除的元素子节点过多，无法保留子元素，请考虑全部删除。");
            }

            //
            // 直接插入
            parent.Children.InsertRange(index, children);

            //
            //
            for (var i = index; i < children.Count; i++)
            {
                var child = parent.Children[i];
                var value = Epoch.Inherit(parent.Value, (byte)(i + 1));

                //
                //
                child.EpochValue = value;
                child.Tier       = (byte)(parent.Tier + 1);

                //
                //
                _system.Update(child.Value);

                ChangeParent(parent, child.Children);
            }
        }

        protected internal void ChangeParent(EpochNode parent, List<EpochNode> children)
        {
            if (children.Count == 0)
            {
                return;
            }

            //
            //
            for (var i = 0; i < children.Count; i++)
            {
                var child = parent.Children[i];
                var value = Epoch.Inherit(parent.Value, (byte)(i + 1));

                //
                //
                child.EpochValue = value;
                child.Tier       = (byte)(parent.Tier + 1);

                //
                //
                _system.Update(child.Value);

                ChangeParent(parent, child.Children);
            }
        }

        //-------------------------------------------------------------
        //
        //          Public Methods
        //
        //-------------------------------------------------------------

        public bool CheckItemExistence(Epoch epoch) => _mapOfEpoch.ContainsKey(epoch.Id);

        #region Add / AddArbitary

        //
        // Backend 指的是数据库
        internal EpochNode AddEpochToBackend(Epoch epoch)
        {
            EpochNode parent;
            int       index;
            uint      value;

            if (EpochLayer is null)
            {
                parent = _RootNodeOfEpoch;
                index  = parent.Children.Count + 1;
                value  = Epoch.Tier1((byte)index);

                epoch.Value = value;
                epoch.Tier  = 1;
            }
            else
            {
                if (!_mapOfEpoch.TryGetValue(EpochLayer.Id, out parent))
                {
                    throw new InvalidDataException("SelectedEpoch属性虽然存在值，但是这个值不在_mapOfEpoch字典当中，值没有被Tracking！");
                }

                if (EpochLayer.Tier > 3)
                {
                    throw new ArgumentOutOfRangeException("父级时期的层数仅能容纳4层，现在已经超出4层！");
                }

                index = parent.Children.Count + 1;
                value = Epoch.Inherit(EpochLayer, (byte)index);

                epoch.Value = value;
                epoch.Tier  = (byte)(EpochLayer.Tier + 1);

            }


            if (parent.Children.Count > 254)
            {
                throw new ArgumentOutOfRangeException("当前时期的父级仅能容纳254个元素，现在已经超出254个！");
            }

            //
            // add to backend
            _system.Add(epoch);
            
            return new EpochNode(parent, epoch);
        }

        /// <summary>
        /// 添加一个时期。
        /// </summary>
        /// <param name="epoch">指定要添加的<see cref="Timelines.Epoch"/>实例。</param>
        public void Add(Epoch epoch)
        {
            if (epoch is null)
            {
                return;
            }

            var node = AddEpochToBackend(epoch);
            _mapOfEpoch.TryAdd(node.Id, node);

            _CountOfEpoch++;
            _VersionOfEpoch++;

            //
            // 添加到UI
            EpochCollection.Add(epoch);
        }

        public void AddArbitary(Epoch epoch)
        {
            if (epoch is null)
            {
                return;
            }
        }

        #endregion

        #region ShiftUp / ShiftDown

        public void ShiftUp(Epoch epoch)
        {
            if (epoch is null)
            {
                return;
            }

            var idxOfEpoch = EpochCollection.IndexOf(epoch);

            //
            // 允许上移的条件，指的是该元素所处的索引必须是[1]或者更高才允许上移
            if (idxOfEpoch < 1)
            {
                return;
            }

            var upItem   = EpochCollection[idxOfEpoch - 1];
            var downItem = EpochCollection[idxOfEpoch];

            //
            // UI层中移动。
            EpochCollection.Move(idxOfEpoch, idxOfEpoch - 1);

            //
            // 交换值。
            (upItem.Value, downItem.Value) = (downItem.Value, upItem.Value);

            //
            // 更新元素
            _system.Update(upItem);
            _system.Update(downItem);


            if (!_mapOfEpoch.TryGetValue(upItem.Id, out var upItemNode) ||
                !_mapOfEpoch.TryGetValue(downItem.Id, out var downItemNode))
            {
                return;
            }


            UpdateSubtree(upItemNode);
            UpdateSubtree(downItemNode);
        }

        public void ShiftDown(Epoch epoch)
        {
            if (epoch is null)
            {
                return;
            }

            var idxOfEpoch = EpochCollection.IndexOf(epoch);

            //
            // 允许上移的条件，指的是该元素所处的索引必须是[1]或者更高才允许上移
            if (idxOfEpoch < 1)
            {
                return;
            }

            var upItem   = EpochCollection[idxOfEpoch];
            var downItem = EpochCollection[idxOfEpoch - 1];

            //
            // UI层中移动。
            EpochCollection.Move(idxOfEpoch, idxOfEpoch - 1);

            //
            // 交换值。
            (upItem.Value, downItem.Value) = (downItem.Value, upItem.Value);

            //
            // 更新元素
            _system.Update(upItem);
            _system.Update(downItem);


            if (!_mapOfEpoch.TryGetValue(upItem.Id, out var upItemNode) ||
                !_mapOfEpoch.TryGetValue(downItem.Id, out var downItemNode))
            {
                return;
            }


            UpdateSubtree(upItemNode);
            UpdateSubtree(downItemNode);
        }

        #endregion

        #region Remove

        private EpochNode RemoveEpochNode(Epoch epoch)
        {
            var node = _mapOfEpoch[epoch.Id];

            if (node is null)
            {
                return null;
            }

            _mapOfEpoch.Remove(node.Id);
            _system.Remove(node.Value);

            //
            // state update 
            _VersionOfEpoch++;
            _CountOfEpoch--;

            //
            //
            return node;
        }

        /// <summary>
        /// 删除当前节点，但保留该节点的子节点。
        /// </summary>
        /// <param name="epoch">要删除的对象。</param>
        /// <remarks>
        /// <para>
        /// <see cref="Epoch"/> 属性的修改，在上层UI中，方法中不维护<see cref="Epoch"/> 属性的值变更。
        /// </para>
        /// <para>
        /// <see cref="EpochLayer"/> 属性的修改，在上层UI中，方法中不维护<see cref="EpochLayer"/> 属性的值变更。
        /// </para>
        /// </remarks>
        public void Remove(Epoch epoch)
        {
            if (epoch is null)
            {
                return;
            }

            var node    = RemoveEpochNode(epoch);
            var index   = node.Parent.Children.IndexOf(node);
            var subTree = node.Children;

            //
            // 移除内容
            node.Parent.Children.Remove(node);

            //
            // 修改父级
            ChangeParent(node.Parent, index, subTree);


            //
            //
            EpochCollection.Remove(epoch);
        }

        /// <summary>
        /// 删除当前节点及该节点的子节点。
        /// </summary>
        /// <param name="epoch">要删除的对象。</param>
        /// <remarks>
        /// <para>
        /// <see cref="Epoch"/> 属性的修改，在上层UI中，方法中不维护<see cref="Epoch"/> 属性的值变更。
        /// </para>
        /// 
        /// <para>
        /// <see cref="EpochLayer"/> 属性的修改，在上层UI中，方法中不维护<see cref="EpochLayer"/> 属性的值变更。
        /// </para>
        /// </remarks>
        public void RemoveSubTree(Epoch epoch)
        {
            if (epoch is null)
            {
                return;
            }

            //
            //
            var node    = RemoveEpochNode(epoch);
            var subTree = GetSubTree(node);

            foreach (var child in subTree)
            {
                //
                // InMem 中移除
                _mapOfEpoch.Remove(child.Id);

                //
                // Database 中移除
                _system.Remove(child.Value);

                //
                // state update 
                _VersionOfEpoch++;
                _CountOfEpoch--;

                //
                // clear children and clear object ref
                child.Children.Clear();
            }

            //
            // 移除
            node.Parent.Children.Remove(node);
            node.Children.Clear();

            //
            // UI 中移除
            EpochCollection.Remove(epoch);

            _VersionOfEpoch++;
            _CountOfEpoch--;
        }

        #endregion

        #region Clear

        public void ClearEpoches()
        {
            //
            //
            _mapOfEpoch.Values
                       .Select(x => x.Value)
                       .ForEach(x => _system.Remove(x));

            //
            //
            ClearEpochStates();
        }

        #endregion

        //-------------------------------------------------------------
        //
        //          Properties
        //
        //-------------------------------------------------------------
        public int CountOfEpoch   => _CountOfEpoch;
        public int VersionOfEpoch => _VersionOfEpoch;

        //-------------------------------------------------------------
        //
        //          UI
        //
        //-------------------------------------------------------------
        public Epoch Epoch      { get; set; }
        public Epoch EpochLayer { get; set; }

        public ObservableCollection<Epoch> EpochLayerList  { get; }
        public ObservableList<Epoch>       EpochCollection { get; }

        //-------------------------------------------------------------
        //
        //          Nested Classes
        //
        //-------------------------------------------------------------
        public sealed class EpochNode
        {
            private EpochNode _parent;
            private byte      _height;



            internal EpochNode()
            {
                _parent  = null;
                _height  = 1;
                Children = new List<EpochNode>(8);
            }

            internal EpochNode(EpochNode parent, Epoch value)
            {
                _parent  = parent;
                _height  = (byte)(parent._height + 1);
                Value    = value;
                Children = new List<EpochNode>(8);

                //
                //
                parent.Children.Add(this);
            }

            internal EpochNode(Epoch value)
            {
                Value    = value;
                Children = new List<EpochNode>(8);
            }

            internal void SetParent(EpochNode parent)
            {
                if (Parent is not null)
                {
                    return;
                }

                _parent = parent;
                _height = (byte)(parent._height + 1);
            }

            internal void AddChildAndSetParent(EpochNode child)
            {
                child.SetParent(this);
                Children.Add(child);
            }

            public string          Id       => Value.Id;
            public EpochNode       Parent   => _parent;
            public byte            Height   => _height;
            public Epoch           Value    { get; }
            public List<EpochNode> Children { get; }

            public string ParentID
            {
                get => Value.ParentID;
                set => Value.ParentID = value;
            }

            public byte Tier
            {
                get => Value.Tier;
                set => Value.Tier = value;
            }

            public uint EpochValue
            {
                get => Value.Value;
                set => Value.Value = value;
            }
        }
    }
}